package com.xh3140.xwidget.app.chart.flowchart;


import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.InsetDrawable;
import android.os.Build;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.SoundEffectConstants;
import android.view.View;
import android.widget.Checkable;
import android.widget.HorizontalScrollView;

import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.Px;
import androidx.appcompat.widget.AppCompatTextView;
import androidx.appcompat.widget.LinearLayoutCompat;
import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat;

import com.xh3140.xwidget.app.R;
import com.xh3140.xwidget.app.utils.DimenUtils;

import java.util.Objects;

@SuppressWarnings("unused")
public class FlowchartView extends HorizontalScrollView {
  @NonNull
  private final ContentInnerLayout mContentInnerLayout;
  @ColorInt
  private int mDefaultColor;
  @ColorInt
  private int mCheckedColor;
  @Px
  private int mBorderWidth;
  @Px
  private int mBorderRadius;
  @Nullable
  private String mFlowchartList;
  @Nullable
  private ItemView mCheckedView;
  @Nullable
  private OnItemViewCreatedListener mOnItemViewCreatedListener;

  @Nullable
  private OnCheckedChangeListener mOnCheckedChangeListener;

  public FlowchartView(@NonNull Context context) {
    this(context, null);
  }

  public FlowchartView(@NonNull Context context, @Nullable AttributeSet attrs) {
    this(context, attrs, 0);
  }

  public FlowchartView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
    this(context, attrs, defStyleAttr, 0);
  }

  public FlowchartView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
    super(context, attrs, defStyleAttr, defStyleRes);
    final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.FlowchartView, 0, 0);
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
      saveAttributeDataForStyleable(context, R.styleable.FlowchartView, attrs, a, defStyleAttr, 0);
    }
    try {
      mDefaultColor = a.getColor(R.styleable.FlowchartView_default_color, 0xFF1C1C1C);
      mCheckedColor = a.getColor(R.styleable.FlowchartView_checked_color, 0xFFFF4500);
      mBorderWidth = a.getDimensionPixelSize(R.styleable.FlowchartView_border_width, DimenUtils.dp2px(context, 2));
      mBorderRadius = a.getDimensionPixelSize(R.styleable.FlowchartView_border_radius, DimenUtils.dp2px(context, 8));
      mFlowchartList = a.getString(R.styleable.FlowchartView_flowchart_list);
    } finally {
      a.recycle();
    }
    mContentInnerLayout = new ContentInnerLayout(context);
    if (mFlowchartList != null) {
      final String[] texts = mFlowchartList.split("->");
      for (String text : texts) {
        mContentInnerLayout.addFlowChildView(text);
      }
    }
    addView(mContentInnerLayout, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
    setHorizontalScrollBarEnabled(false);
  }

  public void setCheckedView(int index) {
    setCheckedView((ItemView) mContentInnerLayout.getChildAt(index));
  }

  private void setCheckedView(@Nullable ItemView view) {
    if (mCheckedView != view) {
      if (mCheckedView != null) {
        mCheckedView.setChecked(false);
      }
      mCheckedView = view;
      if (mCheckedView != null && !mCheckedView.isChecked()) {
        mCheckedView.setChecked(true);
      }
    }
  }

  @ColorInt
  public int getDefaultColor() {
    return mDefaultColor;
  }

  public void setDefaultColor(@ColorInt int color) {
    if (mDefaultColor != color) {
      mDefaultColor = color;
      mContentInnerLayout.updateDivider();
      mContentInnerLayout.updateAllChildViews();
    }
  }

  @ColorInt
  public int getCheckedColor() {
    return mCheckedColor;
  }

  public void setCheckedColor(int color) {
    if (mCheckedColor != color) {
      mCheckedColor = color;
      mContentInnerLayout.updateAllChildViews();
    }
  }

  @Px
  public int getBorderWidth() {
    return mBorderWidth;
  }

  public void setBorderWidth(@Px int width) {
    if (mBorderWidth != width) {
      mBorderWidth = width;
      mContentInnerLayout.updateAllChildViews();
    }
  }

  @Px
  public int getBorderRadius() {
    return mBorderRadius;
  }

  public void setBorderRadius(@Px int radius) {
    if (mBorderRadius != radius) {
      mBorderRadius = radius;
      mContentInnerLayout.updateAllChildViews();
    }
  }

  @Nullable
  public String getFlowchartList() {
    return mFlowchartList;
  }

  public void setFlowchartList(@Nullable String flowchartList) {
    if (!Objects.equals(mFlowchartList, flowchartList)) {
      mFlowchartList = flowchartList;
      mContentInnerLayout.removeAllViews();
      if (mFlowchartList != null) {
        final String[] texts = mFlowchartList.split("->");
        for (String text : texts) {
          mContentInnerLayout.addFlowChildView(text);
        }
      }
    }
  }

  public void setOnItemViewCreatedListener(@Nullable OnItemViewCreatedListener listener) {
    mOnItemViewCreatedListener = listener;
  }

  public void setOnCheckedChangeListener(@Nullable OnCheckedChangeListener listener) {
    mOnCheckedChangeListener = listener;
  }

  public interface OnItemViewCreatedListener {
    void onCreated(@NonNull ItemView itemView);
  }

  public interface OnCheckedChangeListener {
    void onCheckedChanged(@NonNull FlowchartView view, @NonNull ItemView itemView, boolean checked);
  }

  public class ItemView extends AppCompatTextView implements Checkable {
    private final int mPosition;
    private boolean mChecked;

    private ItemView(@NonNull Context context, int position, @Nullable CharSequence text) {
      super(context);
      setFocusable(true);
      setClickable(true);
      setGravity(Gravity.CENTER);
      setTextSize(Color.BLACK);
      setTextSize(16f);
      int padding = DimenUtils.dp2px(context, 8);
      setPaddingRelative(padding, padding, padding, padding);
      updateView();
      setText(text);
      mPosition = position;
      if (mOnItemViewCreatedListener != null) {
        mOnItemViewCreatedListener.onCreated(this);
      }
    }

    public void updateView() {
      setTextColor(mChecked ? mCheckedColor : mDefaultColor);
      final GradientDrawable drawable = new GradientDrawable();
      drawable.setStroke(mBorderWidth, mChecked ? mCheckedColor : mDefaultColor);
      drawable.setCornerRadius(mBorderRadius);
      setBackground(drawable);
    }

    @Override
    public boolean isChecked() {
      return mChecked;
    }

    @Override
    public void setChecked(boolean checked) {
      if (mChecked != checked) {
        mChecked = checked;
        if (checked) {
          setCheckedView(this);
        }
        updateView();
        if (mOnCheckedChangeListener != null) {
          mOnCheckedChangeListener.onCheckedChanged(FlowchartView.this, this, checked);
        }
      }
    }

    @Override
    public void toggle() {
      if (!isChecked()) {
        setChecked(!mChecked);
      }
    }

    @Override
    public boolean performClick() {
      toggle();
      final boolean handled = super.performClick();
      if (!handled) {
        playSoundEffect(SoundEffectConstants.CLICK);
      }
      return handled;
    }

    public int getPosition() {
      return mPosition;
    }
  }

  private class ContentInnerLayout extends LinearLayoutCompat {

    public ContentInnerLayout(@NonNull Context context) {
      super(context);
      setOrientation(LinearLayoutCompat.HORIZONTAL);
      setShowDividers(LinearLayoutCompat.SHOW_DIVIDER_MIDDLE);
      updateDivider();
    }

    public void updateDivider() {
      final VectorDrawableCompat divider = VectorDrawableCompat.create(getResources(), R.drawable.divider_flowchart_arrow, getContext().getTheme());
      if (divider != null) {
        divider.setTint(mDefaultColor);
        setDividerDrawable(new InsetDrawable(divider, DimenUtils.dp2px(getContext(), 4)));
      }
    }

    public void updateAllChildViews() {
      final int childCount = getChildCount();
      for (int i = 0; i < childCount; ++i) {
        final View child = getChildAt(i);
        if (child instanceof ItemView) {
          ((ItemView) child).updateView();
        }
      }
    }

    public void addFlowChildView(@Nullable String text) {
      final int position = getChildCount();
      final ItemView itemView = new ItemView(getContext(), position, text);
      if (itemView.isChecked()) {
        setCheckedView(itemView);
      }
      addView(itemView, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
    }
  }
}
